#include "./Polygon.h"
#include <stdio.h>

// declaration so can use in drawPolygon(); is there a way around this?
//    perhaps move all of the extra functions (or those needed) into here?
void setFramebuffer(int x, int y, float z, float R, float G, float B);
//bool PointCompare(Point* p1, Point* p2);
double intersection(Point p1, Point p2, Point p3, Point p4);
Color lightingEquation(Normal normal);
float dot(Normal n1, Normal n2);



/***********************************  Random  ******************************************/

bool
compareEdge(Edge first, Edge second)
{
	if(first.currentX < second.currentX)
		return true;
	else
		return false;
}


float
dot(Normal n1, Normal n2)
{
	float rvalue;

	rvalue = (n1.x*n2.x + n1.y*n2.y + n1.z*n2.z);

	return rvalue;
}

/***********************************  Color  ******************************************/

Color::Color()
{
	r = g = b = 0;
}

Color::Color(float _r, float _g, float _b)
{
	r = _r;
	g = _g;
	b = _b;
}

Color::~Color()  {  }


// Clamps RGB values to [0,1]
void 
Color::clamp()
{
	if(r < 0)
		r = 0;
	if(g < 0)
		g = 0;
	if(b < 0)
		b = 0;

	if(r > 1)
		r = 1;
	if(g > 1)
		g = 1;
	if(b > 1)
		b = 1;
}


/***********************************  Point  ******************************************/

Point::Point()
{
	x = y = z = 0;
}


Point::Point(double _x, double _y, double _z)
{
	x = _x;
	y = _y;
	z = _z;
}


Point::~Point()  
{
	x = y = z = 0;
}


// Normalizes a vector; not really used in a purely "Point" context
void
Point::normalize()
{
	float magnitude;

	magnitude = sqrt(x*x + y*y + z*z);

	x /= magnitude;
	y /= magnitude;
	z /= magnitude;
}

Point 
Point::operator-(Normal& rhs)
{
	Normal rvalue;
	rvalue.x = this->x - rhs.x;
	rvalue.y = this->y - rhs.y;
	rvalue.z = this->z - rhs.z;
	return rvalue;
}

/*
bool PointCompare(Point* p1, Point* p2)
{
	return ((p1->x == p2->x) && (p1->y == p2->y));
}
*/

/***********************************  Edge  ******************************************/
Edge::Edge()	// hopefully never used
{
	p1 = p2 = Point(0,0,0);
	minY = maxY = currentX = xyIncr = 0;
	horizontal = false;
}


Edge::Edge(Point _p1, Point _p2)
{
	horizontal = false;

	double xyslope;

	p1 = _p1;		
	p2 = _p2;		
	
	if(_p1.y > _p2.y)	// _p1 is the higher y value (lower placed) point
	{
		maxY = (int)_p1.y;	// do want to keep minY, maxY as ints
		minY = (int)_p2.y;
		currentX = _p2.x;

		xyslope = ((double)_p1.y - (double)_p2.y)/((double)_p1.x - (double)_p2.x);	// (y2-y1)/(x2-x1)
		xyIncr = 1/xyslope;
	}
	else if(_p2.y > _p1.y)	// _p2 is the higher y value (lower placed) point
	{
		maxY = (int)_p2.y;	// do want to keep minY, maxY as ints
		minY = (int)_p1.y;
		currentX = _p1.x;
		
		xyslope = ((double)_p2.y - (double)_p1.y)/((double)_p2.x - (double)_p1.x);	// (y2-y1)/(x2-x1)
		xyIncr = 1/xyslope;
	}
	else	// horizontal!  Choose _p1 to be max (though think it should actually just ignore this edge?)
	{
		horizontal = true;

		p1 = (p1.x < p2.x) ? _p1 : _p2;
		p2 = (p1.x < p2.x) ? _p2 : _p1;

		minY = _p1.y;	// do nothing
		maxY = minY + 1;
		currentX = _p1.x;

		xyslope = 0;
		xyIncr = 0;	// technically undefined; will deal with horizontal lines in drawPolygon
	}	
}


Edge::~Edge()  {   }	// nothing needed to implement destructor


bool
Edge::operator<(Edge& rhs)
{
	return (this->currentX < rhs.currentX);
}

// used for debugging
void
Edge::printEdge()
{
	printf("p1:\t%d,%d\tp2:\t%d,%d\ncurrentX:\t%f\txyIncr:\t%f\tminY:\t%f\tmaxY:\t%f\n",
		p1.x, p1.y, p2.x, p2.y, currentX, xyIncr, minY, maxY);
}


/***********************************  EdgeList  ******************************************/
EdgeList::EdgeList(Edge _e)
{
	elmaxY = _e.maxY;	// store the scanline value
	elminY = _e.minY;
}

/*
EdgeList::EdgeList(Edge* _e)
{
	this->elmaxY = _e->maxY;
	this->elminY = _e->minY;
}
*/

EdgeList::EdgeList()
{
	elmaxY = 0;
	elmaxY = 0;
}

EdgeList::~EdgeList() { 
// Have converted to real components - a customized destructor is unnecessary

/*
	std::list<Edge*>::iterator elIter = edgeList.begin();
	Edge* eP;

	// delete and free each edge e
	while(elIter != edgeList.end())
	{
		eP = (*elIter);
		elIter = edgeList.erase(elIter);
		free(eP);
	}
*/
}	


void
EdgeList::addEdge(Edge _e)
{
	if(edgeList.empty())	// empty case
		elminY = _e.minY;
	
	if(_e.minY < elminY)	// update the max/min
		elminY = _e.minY;
	
	if(_e.maxY > elmaxY)
		elmaxY = _e.maxY;

	edgeList.push_back(_e);
	edgeList.sort();
}


void
EdgeList::printEdgeList()	// for debugging
{
	std::list<Edge>::iterator elIter;

	// at each edge, print the two points
	for(elIter = edgeList.begin(); elIter != edgeList.end(); elIter++)
		printf("p1:\t%f,%f\tp2:\t%f,%f\n", (*elIter).p1.x, (*elIter).p1.y,
			(*elIter).p2.x, (*elIter).p2.y);

}


// compares EdgeLists via their "y" value
bool 
EdgeList::compareEdgeList(EdgeList first, EdgeList second)
{
	if(first.elminY < second.elminY)
		return true;
	else
		return false;	
}


bool
EdgeList::operator<(EdgeList& rhs)
{
	return (this->elminY < rhs.elminY);
}

/***********************************  Face  ******************************************/
Face::Face()	// hopefully never used
{	// Everything equals 0
	v1 = v2 = v3 = vNormals[0] = vNormals[1] = vNormals[2] = Point(0,0,0);
//	e1 = e2 = e3 = Edge(Point(0,0,0),Point(0,0,0));
	minY = maxY = vNum[0] = vNum[1] = vNum[2] = 0;
	flatColor = lightingEquation(Normal(0,0,-1));
}

Face::Face(Point p1, Point p2, Point p3, int vNum1, int vNum2, int vNum3)
{
	// Assign vertices (in order)
	v1 = p1;
	v2 = p2;
	v3 = p3;

	// hold the indices of the vertices (for calculating normals when constructing the full Polygon
	vNum[0] = vNum1;
	vNum[1] = vNum2;
	vNum[2] = vNum3;

	// minY = min(v1.y, v2.y, v3.y)
	// maxY = max(v1.y, v2.y, v3.y)
	minY = std::min(std::min(v1.y,v2.y),std::min(v1.y,v3.y));
	maxY = std::max(std::max(v1.y,v2.y),std::max(v1.y,v3.y));

//	e1 = Edge(v1,v2);
//	e2 = Edge(v1,v3);
//	e3 = Edge(v2,v3);


	// Thinking on it, simply keep a vector of Normals in the Polygon; since each face knows the index of
	//   its vertices, can simply use the vector<Normal> in Polygon to find the averaged normal
	// Further thinking => getColor would have to be a function of Polygon (and would be a pain); it'd 
	//   be more logical to get colors as a Face function
	vNormals[0] = vNormals[1] = vNormals[2] = Normal(0,0,0);	// The normals at each of the vertices will be initialized to 
																//   zero until the Polygon updates them in updatePolygon()

	Normal v1v3, v1v2;

	v1v3 = v3 - v1;
	v1v2 = v2 - v1;

	// the face's normal = (v3-v1)x(v2-v1)   <-- cross product
	faceNormal = Normal((v1v3.y*v1v2.z - v1v3.z*v1v2.y),(v1v3.z*v1v2.x - v1v2.z*v1v3.x),(v1v3.x*v1v2.y - v1v3.y*v1v2.x));	
	faceNormal.normalize();

	// all faces will be created while the lighting mode is FLAT
	flatColor = lightingEquation(faceNormal);
}

Face::~Face() { }


/********************************************************************
 Get the Z value on a face associated with a particular x and y 
   coordinate. The equation of a plane is normal*(r-r0)=0; that is, 
   a normal dotted with a vector on the plane minus an offset = 0, so 

   nx(x-x0) + ny(y-y0) + nz(z-z0) = 0;
 <=>
   z = -1*(nx(x-x0) + ny(y-y0) + nz*z0)/nz


*********************************************************************/
float
Face::getZ(float x, float y)
{
	float z, x0, y0, z0;
	x0 = v3.x;
	y0 = v3.y;
	z0 = v3.z;

	Normal n = faceNormal;
	
	z = ((n.x*(x-x0) + n.y*(y-y0) - n.z*z0)/(-1*n.z));

//	float xzslope, yzslope, float z;

	// z is the dependent variable
//	xzslope = (v2.z - v1.z)/(v2.x - v1.x);
//	yzslope = (v2.z - v1.z)/(v2.y - v1.y);

	// z = (xzslope)*x + (yzslope)*y + offset of plane
//	z = v1.z + (xzslope)*x + (yzslope)*y;

	return z;
}


/********************************************************************
 Get the RGB value associated with a certain point on a face.
   * Dependent on the shading mode (flat, Gouraud, Phong)
   * Dependent on current coordinate (if not flat)

 Once again, could generalize, but all faces are triangles - no need
********************************************************************/
Color 
Face::getColor(float x, float y, ShadingMode shadingmode)
{
	Color color;

	if(shadingmode == FLAT)
	{	// simple case - depends on faceNormal
		color = flatColor;
	}
	else
	{
		Normal n1, n2, n3;
		n1 = vNormals[0];
		n2 = vNormals[1];
		n3 = vNormals[2];

		if(shadingmode == GOURAUD)
		{	// find colors at vertices, parameterize, plug and chug
			Color c1, c2, c3;

			c1 = lightingEquation(n1);
			c2 = lightingEquation(n2);
			c3 = lightingEquation(n3);

			// parameterize, interpolate to desired point
			color.r = interpolate(x,y,c1.r,c2.r,c3.r);
			color.g = interpolate(x,y,c1.g,c2.g,c3.g);
			color.b = interpolate(x,y,c1.b,c2.b,c3.b);

			if(color.r >= 1)
				printf("Problem!\n");
		}

		else if(shadingmode == PHONG)
		{	// find normal at point in question, plug and chug
			Normal normal;

			// parameterize, interpolate, renormalize to find target normal
			normal.x = interpolate(x,y,n1.x,n2.x,n3.x);
			normal.y = interpolate(x,y,n1.y,n2.y,n3.y);
			normal.z = interpolate(x,y,n1.z,n2.z,n3.z);
			normal.normalize();

			// plug in
			color = lightingEquation(normal);
		}

		else
			printf("Not a valid shading mode!\n");
	}

	return color;

}



/**********************************************************************
 Interpolate a float value across a face, given the values at each 
   vertex (in order)

 Kind of cheating in that I'm disregarding Z to make it a 2-d problem.
   It shouldn't make too much of a difference and can be fixed later

**********************************************************************/
float
Face::interpolate(float targetX, float targetY, float p1, float p2, float p3)
{
//	float targetZ = getZ(targetX, targetY);
	float yt1, yt2, yt3, xp1, xp2, xp3, pp1, pp2, pp3;
	float x1, x2, ip1, ip2;
	float t, interpValue;

	// On the vertex case
	if((targetX == v1.x) && (targetY == v1.y))
		return p1;
	
	if((targetX == v2.x) && (targetY == v2.y))
		return p2;

	if((targetX == v3.x) && (targetY == v3.y))
		return p3;

	// Horizontal line case
	if((targetY == v1.y) && (targetY == v2.y))	// along v1v2
	{
		x1 = v1.x;
		x2 = v2.x;
		ip1 = p1;
		ip2 = p2;
	}
	else if((targetY == v2.y) && (targetY == v3.y))	// along v2v3
	{
		x1 = v2.x;
		x2 = v3.x;
		ip1 = p2;
		ip2 = p3;
	}
	else if((targetY == v1.y) && (targetY == v3.y))	// along v1v3
	{
		x1 = v1.x;
		x2 = v3.x;
		ip1 = p1;
		ip2 = p3;
	}

	else
	{
		Edge e1 = Edge(v1,v2);
		Edge e2 = Edge(v1,v3);
		Edge e3 = Edge(v2,v3);

		// Start by parameterizing the edges; find the parameter at target y
		yt1 = (targetY - v1.y)/(v2.y - v1.y);
		yt2 = (targetY - v1.y)/(v3.y - v1.y);
		yt3 = (targetY - v2.y)/(v3.y - v2.y);

		// can extract x values at that y value using this parameter 
		xp1 = v2.x*yt1 + v1.x*(1 - yt1);
		xp2 = v3.x*yt2 + v1.x*(1 - yt2);
		xp3 = v3.x*yt3 + v2.x*(1 - yt3);

		// and parameterizing the interpolate values will give the values along the edge
		//   at y = targetY (and x = xp*)
		pp1 = p2*yt1 + p1*(1 - yt1);
		pp2 = p3*yt2 + p1*(1 - yt2);
		pp3 = p3*yt3 + p2*(1 - yt3);

		// check if the parameter values (yt*) are in [0,1]; use those edge's results
		if((yt1 <= 0) || (yt1 >= 1))
		{	// use e2 and e3 values
			x1 = xp2;
			x2 = xp3;
			ip1 = pp2;
			ip2 = pp3;
		}

		else if((yt2 <= 0) || (yt2 >= 1))
		{	// use e1 and e3 values
			x1 = xp1;
			x2 = xp3;
			ip1 = pp1;
			ip2 = pp3;
		}

		else if((yt3 <= 0) || (yt3 >= 1))
		{	// use e1 and e2 values
			x1 = xp1;
			x2 = xp2;
			ip1 = pp1;
			ip2 = pp2;
		}
	}

	// find parameter value at targetX
	t = (targetX - x1)/(x2 - x1);

	//find parameter value at that point
	interpValue = ip2*t + ip1*(1 - t);

	return interpValue;
}


/*************************************************************************
 Applies the lighting equation given a normal vector.  In this assignment
   all the coefficients and light sources are given and thus explicitly 
   defined here, though this could be generalized to accept coefficients
   and light sources

*************************************************************************/
Color lightingEquation(Normal normal)
{
	Color ambient, diffuse, specular, final;
	Color ka, kd, ks;	// values from assignment webpage
	ka = Color(0.1,0,0);	// ka = [0.1,0,0]
	kd = Color(0.7,0,0);	// kd = [0.7,0,0]	
	ks = Color(0.5,0.5,0.5);	// ks = [0.5, 0.5, 0.5]
	
	int se = 5;	// specular exponent

	// Light location: -infinity (i.e. behind viewer)
	// Light direction: toward source; is really a vector rather than a normal
	// light shines in [-1,-1,1] direction; vector should point *to* light
	Normal lightDirection = Normal(1,1,-1);	
	lightDirection.normalize();
	Color lightSource = Color(1,1,1);	// lightsource = [1,1,1]
	
	Color ambientLight = Color(0.5,0.5,0.5);
	
	Normal eye = Normal(0,0,-1);
	eye.normalize();

	// Lighting Equation: I = ka*A + C(kd(L.N)+ks(R.E)^n)
// Ambient
	ambient.r = ka.r*ambientLight.r;
	ambient.g = ka.g*ambientLight.g;
	ambient.b = ka.b*ambientLight.b;
	ambient.clamp();

// Diffuse
	float LdotN = dot(lightDirection,normal);
	diffuse.r = lightSource.r*kd.r*LdotN;
	diffuse.g = lightSource.g*kd.g*LdotN;
	diffuse.b = lightSource.b*kd.b*LdotN;
	diffuse.clamp();

// Specular
	// R = 2*(L.N)N - L
	Normal sRefl;	// reflected specular light
	sRefl.x = 2*LdotN*normal.x - lightDirection.x;
	sRefl.y = 2*LdotN*normal.y - lightDirection.y;
	sRefl.z = 2*LdotN*normal.z - lightDirection.z;
	sRefl.normalize();

	float RdotE = dot(sRefl, eye);
	float alpha = pow(RdotE,se);	// raise R.E to the specular coefficient's power

	specular.r = lightSource.r*ks.r*alpha;	// lightsource = [1,1,1]
	specular.g = lightSource.g*ks.g*alpha;
	specular.b = lightSource.b*ks.b*alpha;
	specular.clamp();



// Intensity
	final.r = ambient.r + diffuse.r + specular.r;
	final.g = ambient.g + diffuse.g + specular.g;
	final.b = ambient.b + diffuse.b + specular.b;

	return final;
}


/***********************************  FaceList  ******************************************/
FaceList::FaceList() 
{	
/** Initializing flminY to 0 could pose problems when adding a face; because we want
 *    to keep flminY the minimum minY value in the FaceList, we cannot simply reassign
 *    the values every time a new face is added, but 0 will be less than the 
 *    values to be added; to deal with this, a test of whether the FaceList's faceList is
 *    empty is performed when in addFace - if it is empty, flminY is assigned to equal
 *    the new face's minY; if not, a comparison is done between the two.
 */
	flminY = flmaxY = 0;
}

FaceList::~FaceList() { }

void
FaceList::addFace(Face _f)
{
/** Initializing flminY to 0 could pose problems when adding a face; because we want
 *    to keep flminY the minimum minY value in the FaceList, we cannot simply reassign
 *    the values every time a new face is added; thus the logical conclusion is to
 *    do a test between flminY and the new minY.  However, 0 will be less than the 
 *    values to be added; to deal with this, a test of whether the FaceList's faceList is
 *    empty is performed when adding a face - if it is empty, flminY is assigned to equal
 *    the new face's minY; if not, a comparison is done between the two.  Thus, unless measures
 *    are taken to consider the original case, do not remove the conditional clause below
 */
	if(faceList.empty())
		flminY = _f.minY;

	faceList.push_back(_f);
	
//	flminY = (flminY <= _f.minY) ? flminY : _f.minY;	// spelled out for clarity
	if(flminY <= _f.minY)
		;	// do nothing
	else
		flminY = _f.minY;

//	flmaxY = (flmaxY >= _f.maxY) ? flmaxY : _f.maxY;	// spelled out for clarity
	if(flmaxY >= _f.maxY)
		;	// do nothing
	else
		flmaxY = _f.maxY;
}

void
FaceList::clear()
{
	faceList.clear();	// empties the faceList
}


// compares FaceLists via their "minY" value
bool 
FaceList::compareFaceList(FaceList first, FaceList second)
{
	if(first.flminY < second.flminY)
		return true;
	else
		return false;	
}


bool
FaceList::operator<(FaceList& rhs)
{
	return (this->flminY < rhs.flminY);
}


/***********************************  Polygon  ******************************************/
Polygon::Polygon() { }

Polygon::Polygon(int _windowWidth, int _windowHeight) {
	windowWidth = _windowWidth;
	windowHeight = _windowHeight;	
}

Polygon::~Polygon() {

	/* Since I have made the transition to real objects instead of pointers,
	 *   there should be no reason to explicitly destroy each member of the 
	 *   afTable - the destructor is not needed
	 */

/*
	std::list<FaceList>::iterator aftIter = afTable.begin();
	FaceList* flp;

	// delete and free each edgelist e in the afTable
	while(aftIter != afTable.end())
	{
		flp = &(*aftIter);
		aftIter = afTable.erase(aftIter);
		free(flp);
	}
*/

	//delete afList // not needed
}

void 
Polygon::addVertex(Point _p)
{
/* the .obj file is assumed to be in order; something more complicated (e.g. adding an index 
	field to the Point class and sorting by that) could be rigged for the general case, but
	this suffices   */
	vertices.push_back(_p);	
}

void 
Polygon::addFace(Face f)
{
	faces.addFace(f);

	/*
	std::list<FaceList>::iterator iter, next;

	for(iter = afTable.begin(); iter != afTable.end(); iter++)
	{
		if((*iter).flminY == f.minY)	// correct EdgeList
		{
			(*iter).addFace(f);	// add an edge at that point
			return;
		}
	}

	// no correct scanline value was found 
	//    => add a new FaceList with the correct scanline value
	FaceList fl;						// new EdgeList
	fl.addFace(f);						// will update in addFace to consider proper scanline

	afTable.push_back(fl);				// stick the EdgeList in the table
	afTable.sort();						// make sure the table is in order (wrt. minY)
	*/
}

void
Polygon::addFace(int vNum1, int vNum2, int vNum3)	// given the Polygon's vertex numbers
{
	// First, make the face
	// subtract 1 to get to the correct vertex; unlike vectors, the vertex numbers begin at 1, not 0
	Face f = Face(vertices.at(vNum1 - 1), vertices.at(vNum2 - 1), vertices.at(vNum3 - 1), vNum1, vNum2, vNum3);

	// Next, add the face; can use the other addFace()  (this one is needed mostly to access the 
	//   vector of vertices)
	addFace(f);	// should add to this Polygon
}


/*************************************************************************************
 This function serves to
   * assign each vertex a normal, equal to the average of the adjacent faces' normals

*************************************************************************************/
void
Polygon::updatePolygon()
{
	afList.clear();	// will utilize the afList member for the averaging
	vertexNormals.clear();	// so that the indices are all the same (though still off by one)

	std::vector<Point>::iterator pIter;
	std::list<Face>::iterator fIter;
//	std::list<FaceList>::iterator fListIter;

	int currentVertexIndex = 1;

	for(pIter = vertices.begin(); pIter != vertices.end(); pIter++)
	{	// for each vertex, while keeping track of the vertex index

		printf("Updating %d\n", currentVertexIndex);


		// 1. go through and find adjacent faces
		for(fIter = faces.faceList.begin(); fIter != faces.faceList.end(); fIter++)
		{	// for each face
			for(int i = 0; i < 3; i++)	// since there are 3 vertices in a triangle and 3 members to vNum[]
			{	// check vertex indices
				if((*fIter).vNum[i] == currentVertexIndex)	// if the index is part of the face
					afList.addFace((*fIter));				// add the face to the afList
			}
		}


/*		
		for(fListIter = afTable.begin(); fListIter != afTable.end(); fListIter++)
		{	// for each FaceList in the afTable
			for(fIter = (*fListIter).faceList.begin(); fIter != (*fListIter).faceList.end(); fIter++)
			{	// for each Face
				for(int i = 0; i < 3; i++)	// since there are 3 vertices in a triangle and 3 members to vNum[]
				{
					if((*fIter).vNum[i] == currentVertexIndex)	// if the index is part of the face
						afList.addFace((*fIter));				// add the face to the afList
				}
			}
		}
*/

		// 2. average the normals
		float avgX, avgY, avgZ;	// for the average of the normals
		avgX = avgY = avgZ = 0;

		// 2a. Sum the components of the normals
		for(fIter = afList.faceList.begin(); fIter != afList.faceList.end(); fIter++)
		{
			avgX += (*fIter).faceNormal.x;
			avgY += (*fIter).faceNormal.y;
			avgZ += (*fIter).faceNormal.z;
		}

		// 2b. Divide by the number of elements
		avgX /= afList.faceList.size();
		avgY /= afList.faceList.size();
		avgZ /= afList.faceList.size();

		Normal normal = Normal(avgX, avgY, avgZ);
		normal.normalize();
		
		// 3. update vertexNormals
		vertexNormals.push_back(normal);

		for(fIter = faces.faceList.begin(); fIter != faces.faceList.end(); fIter++)
		{	// for each face
			for(int i = 0; i < 3; i++)	// since there are 3 vertices in a triangle and 3 members to vNum[]
			{	// check vertex indices
				if((*fIter).vNum[i] == currentVertexIndex)	// if the index is part of the face
					(*fIter).vNormals[i] = normal;	// associate the normal with the appropriate vertex Face
			}
		}

		// 4. clear the afList for the next face; update currentVertexIndex
		afList.clear();
		currentVertexIndex++;
	}
}



/******************************************************************************
 Called from inside display()

********************************************************************************/
void 
Polygon::drawPolygon(ShadingMode shadingmode)	// will be the one to call setFrameBuffer();
{
	int line;	// current scanline being drawn
	float z;				// for use in the Z buffer
	Color color;			// will be operated on and passed to setFrameBuffer()
	bool inside = false;	// for determining whether or not to fill in pixels
	bool polyDrew;

	int counter = 1;

	EdgeList aeList, faceEdgeList;

	std::list<FaceList>::iterator afTableIter = afTable.begin();
	std::list<Face>::iterator afListIter;
	std::list<Face>::iterator FaceIter;
	std::list<Edge>::iterator EdgeIter;
	

	for(FaceIter = faces.faceList.begin(); FaceIter != faces.faceList.end(); FaceIter++)
	{	// for each face in the polygon

		printf("Drawing face %d\n", counter);

		line = 0;

		polyDrew = false;	// for debugging; some faces weren't drawing for some reason

		faceEdgeList.edgeList.clear();	// empty it
		aeList.edgeList.clear();
		// Once again, something more complicated could be rigged for the general case, but
		faceEdgeList.addEdge(Edge((*FaceIter).v1,(*FaceIter).v2));	// this works for triangles
		faceEdgeList.addEdge(Edge((*FaceIter).v1,(*FaceIter).v3));
		faceEdgeList.addEdge(Edge((*FaceIter).v2,(*FaceIter).v3));

		while( line < windowHeight )
		{
//			printf("Scanline %d\n",line);

			// 1. Add edges to Active Edge List from the face based on their minimum Y value
			for(EdgeIter = faceEdgeList.edgeList.begin(); EdgeIter != faceEdgeList.edgeList.end(); EdgeIter++)
			{
				if((*EdgeIter).minY == line)	// there is an entry that starts at this scanline
				{
						aeList.addEdge((*EdgeIter));
				}
			}


			// 2. Remove edges that end at that line
			for(EdgeIter = aeList.edgeList.begin(); EdgeIter != aeList.edgeList.end(); EdgeIter++)
			{
				// if an edge ends at this scanline
				while((*EdgeIter).maxY == line)	
				{	// erase the edge
					// erase() returns an iterator to the one after the one that was erased
					EdgeIter = aeList.edgeList.erase(EdgeIter);

					// so that the list iterator is always dereferencable
					if(EdgeIter == aeList.edgeList.end())
						break;
				}

				if(EdgeIter == aeList.edgeList.end())
					break;
			}



			// If there is nothing in the list, there is nothing to draw and no
			//    reason to go on
			if(aeList.edgeList.empty())	// returns 1 if is empty
			{
				line++;					// go to the next line and try again
				continue;				
			}

			if(aeList.edgeList.size() > 2)
			{
				printf("The AEList has more than 2 elements in it..\n");
				printf("It has %d elements\n",aeList.edgeList.size());
			}


			// 3. Fill Pixels
			inside = false;	// toggle pixels on and off as edges are encountered; default is off
			aeList.edgeList.sort(compareEdge);	// sorts by currentX
		
			EdgeIter = aeList.edgeList.begin();
			for(int i = 0; i < windowWidth; i++)	// each x coordinate at y = line
			{
				if(EdgeIter == aeList.edgeList.end())
					break;

				if((*EdgeIter).horizontal == true)	// horizontal line case
				{
					for(int i = (*EdgeIter).p1.x; i < (*EdgeIter).p2.x; i++)
					{
						z = (*FaceIter).getZ(i,line);
						color = (*FaceIter).getColor(i,line,shadingmode);
						setFramebuffer(i, line, z, color.r, color.g, color.b);	// color the pixel!
						if(polyDrew == false)
							polyDrew = true;
					}
					EdgeIter++;
				}

				if(EdgeIter == aeList.edgeList.end())
					break;

				while((*EdgeIter).currentX <= i)	// passed an edge
				{
					inside = !inside;			// invert whether you're coloring or not
					EdgeIter++;				// check the next edge
					if(EdgeIter == aeList.edgeList.end())
						break;
				}

				if(EdgeIter == aeList.edgeList.end())
					break;

				if(inside)						// if inside a polygon
				{
					z = (*FaceIter).getZ(i,line);
					color = (*FaceIter).getColor(i,line,shadingmode);
					setFramebuffer(i, line, z, color.r, color.g, color.b);	// color the pixel!
					if(polyDrew == false)
						polyDrew = true;
				}
			}


			// 4. Increment x-values on edges in Active Edge List
			for(EdgeIter = aeList.edgeList.begin(); EdgeIter != aeList.edgeList.end(); EdgeIter++)	
			{
				(*EdgeIter).currentX += (*EdgeIter).xyIncr;	// incrementing x values on all edges
			}


			// 5. Increment scanline
			line++;

		}

		if(polyDrew == false)
			printf("'Twas false\n");

		counter++;
	}
}

/*
void
Polygon::printEdgeTable()	// for debugging
{
	std::list<FaceList*>::iterator afTableIter;

	for(afTableIter = afTable.begin(); 
		afTableIter != afTable.end(); afTableIter++)
	{
		printf("Edge %d:\n", (*afTableIter)->flminY);
		(*afTableIter)->printEdgeList();
	}

	printf("\n");
}
*/
